/**
 * 智能分割文本函数，根据指定的规则将文本分割成多个片段
 *
 * @param {string} text - 需要分割的文本
 *
 * @param {Object} options - 分割选项
 *
 * @param {number} [options.maxLength=1024] - 每个片段的最大长度
 *
 * @param {number} [options.overlap=0] - 相邻片段之间的重叠长度
 *
 * @param {boolean} [options.preserveSentence=true] - 是否保留句子完整性
 *
 * @param {boolean} [options.preserveParagraph=true] - 是否保留段落完整性
 *
 * @param {boolean} [options.returnObjects=false] - 是否返回包含文本、起始和结束位置的对象数组
 *
 * @returns {Array<string|Object>} - 根据 returnObjects 参数返回字符串数组或对象数组
 */
function splitTextIntelligently(text, options = {}) {
	/**
	 * 解构选项参数，并设置默认值
	 */
	const { maxLength = 1024, overlap = 0, preserveSentence = true, preserveParagraph = true, returnObjects = false } = options;
	// 如果文本为空或长度小于等于最大长度，直接返回结果
	if (!text || text.length <= maxLength) return returnObjects ? [{ text, start: 0, end: text.length }] : [text];
	/**
	 * 用于存储分割后的文本片段
	 */
	const segments = [];
	/**
	 * 当前处理的起始索引
	 */
	let startIndex = 0;
	/**
	 * 查找合适的分割点
	 *
	 * @param {number} start - 查找的起始索引
	 *
	 * @param {number} end - 查找的结束索引
	 *
	 * @returns {number} - 合适的分割点索引
	 */
	const findSplitPoint = (start, end) => {
		// 如果需要保留段落完整性
		if (preserveParagraph) {
			/**
			 * 查找结束索引前最后一个换行符的位置
			 */
			const lastNewLine = text.lastIndexOf('\n', end);
			// 如果换行符位置在起始索引之后，且距离结束索引不超过100个字符，则以换行符为分割点
			if (lastNewLine > start && lastNewLine > end - 100) return lastNewLine + 1;
		}
		// 如果需要保留句子完整性
		if (preserveSentence) {
			/**
			 * 定义句子结束的正则表达式
			 */
			const sentenceEndings = /[。！？!?；;]\s*|[\n\r]+/g;
			/**
			 * 用于存储正则表达式匹配结果的临时变量
			 */
			let match;
			/**
			 * 用于记录最佳分割点的索引，初始化为 -1 表示未找到
			 */
			let bestMatch = -1;
			// 重置正则表达式的 lastIndex 属性
			sentenceEndings.lastIndex = 0;
			/**
			 * 获取起始索引到结束索引之间的子文本
			 */
			const sub = text.substring(start, end);
			// 查找所有句子结束的位置
			while ((match = sentenceEndings.exec(sub)) !== null) {
				/**
				 * 计算在原文本中的实际位置
				 */
				const pos = start + match.index + match[0].length;
				if (pos <= end) bestMatch = pos;
			}
			// 如果找到的匹配位置在起始索引之后，且距离结束索引不超过50个字符，则以该位置为分割点
			if (bestMatch > start && bestMatch > end - 50) return bestMatch;
		}
		// 从结束索引开始向前查找空白字符作为分割点
		for (let i = Math.min(end, text.length - 1); i > start; i--) {
			if (text[i] === ' ' || text[i] === '\t' || text[i] === '\n') return i + 1;
		}
		// 如果没有找到合适的分割点，返回结束索引
		return end;
	};
	// 循环处理文本，直到处理完所有内容
	while (startIndex < text.length) {
		/**
		 * 计算当前片段的结束索引
		 */
		let endIndex = startIndex + maxLength;
		// 如果结束索引超过文本长度，说明已经到文本末尾
		if (endIndex >= text.length) {
			/**
			 * 获取剩余的文本片段
			 */
			const segment = text.substring(startIndex);
			// 如果需要返回对象，将剩余文本作为一个对象添加到数组中
			if (returnObjects) segments.push({ text: segment, start: startIndex, end: text.length });
			// 否则，直接将剩余文本添加到数组中
			else segments.push(segment);
			break;
		}
		/**
		 * 查找合适的分割点
		 */
		const splitPoint = findSplitPoint(startIndex, endIndex);
		/**
		 * 确保分割点在有效范围内
		 */
		const actualSplitPoint = Math.min(Math.max(splitPoint, startIndex + 1), text.length);
		/**
		 * 获取当前分割的文本片段
		 */
		const segment = text.substring(startIndex, actualSplitPoint);
		/**
		 * 移除首尾空格
		 */
		const trimmedSegment = segment.trim();
		// 如果移除空格后为空字符串，直接跳过
		if (trimmedSegment.length === 0) { startIndex = actualSplitPoint; continue; }
		// 如果需要返回对象，将当前片段作为一个对象添加到数组中
		if (returnObjects) segments.push({ text: trimmedSegment, start: startIndex, end: actualSplitPoint });
		// 否则，直接将当前片段添加到数组中
		else segments.push(trimmedSegment);
		// 更新起始索引，考虑重叠部分
		startIndex = actualSplitPoint - Math.min(overlap, actualSplitPoint - startIndex);
	};
	return segments;
};

/**
 * 智能向量分割文本函数，将文本按指定的最大长度和重叠长度进行分割，并返回包含文本、起始和结束位置的对象数组。
 *
 * @param {string} text - 需要分割的文本
 *
 * @param {number} [maxLength=1024] - 每个片段的最大长度，默认为1024
 *
 * @param {number} [overlap=128] - 相邻片段之间的重叠长度，默认为128
 *
 * @returns {Array<Object>} - 返回包含文本、起始和结束位置的对象数组
 */
function splitTextToObjects(text, maxLength = 1024, overlap = 128) {
	return splitTextIntelligently(text, { maxLength, overlap, preserveSentence: true, preserveParagraph: true, returnObjects: true });
};

/**
 * 智能向量分割文本函数，将文本按指定的最大长度和重叠长度进行分割，并返回包含文本数组。
 *
 * @param {string} text - 需要分割的文本
 *
 * @param {number} [maxLength=1024] - 每个片段的最大长度，默认为1024
 *
 * @returns {Array<string>} - 返回分割后的字符串数组
 */
function splitTextToStrings(text, maxLength = 1024) {
    // 调用 splitTextIntelligently 函数进行智能分割，设置重叠长度为50，保留句子和段落完整性，返回字符串数组
    return splitTextIntelligently(text, { maxLength, overlap: 50, preserveSentence: true, preserveParagraph: true, returnObjects: false });
};